<?php
/**
 * Srun3000客户端类
 *
 * @author sskaje sskaje@gmail.com
 * @version 2.0.0
 * @todo 提供一个通信的机制
 */
class sscSrun3000forBIT 
{
	private $username;
	private $password;
	private $mode = 1;
	private $client_type = 1;
	private $n = 1;
	
	private $url_host = '10.0.0.55';
	private $url_port = 3333;
	private $url_login     = 'http://%s:%d/cgi-bin/do_login';
	private $url_logout    = 'http://%s:%d/cgi-bin/do_logout';
	private $url_keepalive = 'http://%s:%d/cgi-bin/keeplive';
	
	private $modes = array(0=>'国际模式', 1=>'国内模式');
	private $client_types = array(
		1=>array('WEB 模式', 1, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'), 
		2=>array('客户端模式', 7, 'my session'),
		3=>array('Linux Client', 99, ''),
	);

	private $user_agent = '';

	private $_mac = '00:0a:42:cd:3c:0a';
	private $_key = '22222222';
	private $time_diff = 0;
	
	private $uid = 0;
	
	public  $debug = 0;
	
	
	/**
	 * cookie文件存放路径
	 *
	 * @var string
	 */
	private $cookie_file = 'cookie.txt';
	/**
	 * 配置文件
	 * 
	 * @var string
	 */
	//private $_config_file = '~/.srun/config';
	private $_config_file = '/tmp/config';
	/**
	 * cURL 资源
	 *
	 * @var cURL
	 */
	private $ch;

	public function __construct()
	{
	}

	/**
	 * 构造函数，默认参数构造
	 *
	 * @param string $username 用户名
	 * @param string $password 密码
	 */
	public function set_login($username, $password)
	{
		$this->username = $username;
		$this->password = $password;
	}
	
	/**
	 * 构造函数，默认参数构造
	 *
	 * @param string $host 主机IP
	 * @param int $port 主机端口
	 */
	public function set_host($host=NULL, $port=NULL)
	{
		if ($host != NULL)
			$this->url_host = $host;
		if ($port != NULL)
			$this->url_port = $port;
		
		$this->url_login     = sprintf($this->url_login,     $this->url_host, $this->url_port);
		$this->url_logout    = sprintf($this->url_logout,    $this->url_host, $this->url_port);
		$this->url_keepalive = sprintf($this->url_keepalive, $this->url_host, $this->url_port);
	}
	
	/**
	 * 设置客户端模式
	 *
	 * @param int $client_type 客户端模式，1->Web，2->客户端
	 */
	public function set_client_type($client_type)
	{
		if (isset($this->client_types[$client_type]))
		{
			$this->client_type = $client_type;
			$this->n           = $this->client_types[$client_type][1];
			$this->user_agent  = $this->client_types[$client_type][2];
		}
		else
		{
			throw new Exception('Bad client type');
		}
	}
	/**
	 * 设置登陆模式
	 *
	 * @param int $mode 登陆模式，1->国内，0->国际
	 */
	public function set_mode($mode)
	{
		if ($mode != 1 && $mode != 0)
		{
			throw new Exception('Bad login mode');
		}
		else if ($mode == 0)
		{
			echo "将以国际模式登陆\n";
		}
		else
		{
			echo "将以国内模式登陆\n";
		}
		$this->mode = $mode;
	}
	/**
	 * 设置cookie文件路径
	 *
	 * @param string $cookie_file
	 */
	public function set_cookie_fileloc($cookie_file)
	{
		$this->cookie_file = $cookie_file;
	}
	/**
	 * 初始化资源
	 *
	 */
	public function init()
	{
		$this->ch = curl_init();
		curl_setopt($this->ch, CURLOPT_VERBOSE, 0);
		curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($this->ch, CURLOPT_COOKIEJAR, $this->cookie_file);

		curl_setopt($this->ch, CURLOPT_PORT, $this->url_port);
		
		if (($ua = $this->client_types[$this->client_type][2]))
		{
			curl_setopt($this->ch, CURLOPT_USERAGENT, $ua);
		}
	}
	/**
	 * 登陆
	 *
	 */
	public function login($i=1)
	{
		$this->generate_enc_key();
		if ($this->client_type == 2)
		{
			$password = $this->passencode($this->password);
		}
		else
		{
			$password = $this->password;
		}

		$login_str = 
			'username=' . urlencode($this->username) . 
			'&password=' . urlencode($password) . 
			'&drop=' . $this->mode . 
			'&type=' . $this->client_type . 
			'&n=' . $this->n . 
			'&mac=' . $this->passencode($this->_mac);

		$this->debug('Login: ' . $this->url_login);
		$this->debug('Login: ' . $login_str);
		

		curl_setopt($this->ch, CURLOPT_URL, $this->url_login);
		curl_setopt($this->ch, CURLOPT_REFERER, $this->url_login);
		curl_setopt($this->ch, CURLOPT_POST, 1);
		curl_setopt($this->ch, CURLOPT_POSTFIELDS, $login_str);
		$out = curl_exec($this->ch);

		$this->debug('Login response: ' . $out);

		curl_setopt($this->ch, CURLOPT_COOKIE, $this->username.'%7C'.$this->password);
		$matches=array();
		
		$res = $this->parse_http_reponse($out);

		if ($this->client_type ==2 && preg_match('#^(\d+),\d+,\d+,\d+,\d+$#', $res['text'], $matches))
		{
			$this->uid = $matches[1];
			return 1;
		}
		else if (
			$this->client_type == 1 && preg_match('#^\d+$#', $res['text'])
			)
		{
			$this->uid = $res['text'];
			return;
		} 
		else if (
			$this->client_type == 3 && preg_match('#^(\d+)`$#', $res['text'], $matches)
			)
		{
			$this->uid = $matches[1];
			return;
		}
		else if (preg_match('#password_error@(\d+)#', $res['text'], $matches))
		{
			$server_time = intval($matches[1]);
			$this->time_diff = $server_time - time();
			if ($i<2 && $this->login(++$i))
			{
				return ;
			}
		}

		$this->login_error($out);
	}
	/**
	 * 注销
	 *
	 */
	public function logout()
	{
		curl_setopt($this->ch, CURLOPT_URL, $this->url_logout);
		curl_setopt($this->ch, CURLOPT_POST, 1);
		$logout_str = 'uid='.$this->uid;

		$this->debug('Logout query: '.$logout_str);

		curl_setopt($this->ch, CURLOPT_POSTFIELDS, $logout_str);
		$out = curl_exec($this->ch);

		$this->debug('Logout: ' . $out);

		$res = $this->parse_http_reponse($out);

		if ($res['text'] == 'logout_ok')
		{
			echo 'Successfully logout.';
		}
		else 
		{
			echo 'Failed to log u out';
		}
	}
	/**
	 * 保持连接
	 *
	 * @return string
	 */
	public function keepalive()
	{
		curl_setopt($this->ch, CURLOPT_URL, $this->url_keepalive);
		curl_setopt($this->ch, CURLOPT_POST, 1);
		$keepalive_str = 'uid='.$this->uid;
		
		$this->debug('Keepalive query: '.$keepalive_str);
		curl_setopt($this->ch, CURLOPT_POSTFIELDS, $keepalive_str);
		$out = curl_exec($this->ch);

		$this->debug('Keepalive: ' . $out);

		$res = $this->parse_http_reponse($out);

		if (preg_match('#^\d+,\d+,\d+$#', $res['text']))
		{
			return $res['text'];
		}
		else
		{
			//return $out;
			die('Disconnected.');
		}
	}

	/**
	 * 客户端模式密码加密
	 *
	 * @param string $pass
	 * @return string
	 */
	public function passencode($pass)
	{
		$pass = substr($pass, 0, 16);
		$len = strlen($pass);
		$ret = '';
		for ($i=0; $i<$len; $i++)
		{
			$_pass = ord($pass[$i]);

			$_key  = $this->_get_keychar($i);

			$_key  = $_key ^ $_pass;
			$ret .= $this->_build_key($_key, $i%2);
		}
		return $ret;
	}
	/**
	 * 生成密钥
	 *
	 */
	public function generate_enc_key()
	{
		$this->_key = strval(floor((time() + $this->time_diff)/60));
	}
	/**
	 * 算出每次加密所用的字符
	 *
	 */
	private function _get_keychar($num)
	{
		$len = strlen($this->_key);
		return ord($this->_key[ $len - $num % $len - 1 ]);
	}
	/**
	 * 加密字符
	 *
	 */
	private function _build_key($num, $reverse=0)
	{
		$ret = '';
		
		$_low = $num & 0x0f;
		
		$_high = $num >> 4;
		$_high = $_high & 0x0f;
		
		if (!$reverse)
		{
			$ret .= chr($_low  + 0x36);
			$ret .= chr($_high + 0x63);
		}
		else
		{
			$ret .= chr($_high + 0x63);
			$ret .= chr($_low  + 0x36);
		}
		return $ret;
	}
	/**
	 * 登陆提示
	 *
	 * @param string $out
	 */
	public function login_error($out)
	{
		switch($out)
		{
		case "user_tab_error":
			die("认证程序未启动");
			break;
		
		case "username_error":
			die("用户名错误");
			break;
		
		case "non_auth_error":
			echo "您无须认证，可直接上网";
			break;
		
		case "password_error":
			die("密码错误");
			break;
		
		case "status_error":
			die("用户已欠费，请尽快充值。");
			break;
		
		case "available_error":
			die("用户已禁用");
			break;
		
		case "ip_exist_error":
			die("用户已存在");
			break;
		
		case "usernum_error":
			die("用户数已达上限");
			break;
		
		case "online_num_error":
			die("该帐号的登录人数已超过限额\n如果怀疑帐号被盗用，请联系管理员。");
			break;
		
		case "mode_error":
			die("系统已禁止WEB方式登录，请使用客户端");
			break;
		
		case "time_policy_error":
			die("当前时段不允许连接");
			break;
		
		case "flux_error":
			die("您的流量已超支");
			break;
		
		case "minutes_error":
			die("您的时长已超支");
			break;
		
		case "ip_error":
			die("您的IP地址不合法");
			break;
		
		case "mac_error":
			die("您的MAC地址不合法");
			break;
		
		default:
			die("找不到认证服务器");
			break;
		}
	}
	/**
	 * debug数据
	 *
	 * @param string $message
	 */
	public function debug($message)
	{
		if ($this->debug)
			echo "\n=====================================\n[DEBUG] ", date('Ymd H:i:s ') ,$message, "\n=====================================\n";
	}
	/**
	 * 查询状态
	 *
	 */
	public function query()
	{
		$msg = $this->keepalive();
		$nums = explode(',', $msg);
		echo "
Username: {$this->username}
UID     : {$this->uid}
Mode    : {$this->modes[$this->mode]}
Type    : {$this->client_types[$this->client_type][0]}

Data in : {$nums[1]} bytes
Data out: {$nums[2]} bytes
Connection time: {$nums[0]} seconds
";
	}
	
	/**
	 * 写配置文件
	 *
	 */
	public function write_config()
	{
		//die(dirname($this->_config_file));
		if (!file_exists(dirname($this->_config_file)))
			mkdir(dirname($this->_config_file));
		$config = <<<CONFIG
[srun]
server_host={$this->url_host}
server_port={$this->url_port}
time_diff={$this->time_diff}
username=
password=
mode={$this->mode}
mac={$this->_mac}
client_type={$this->client_type}

CONFIG;
		file_put_contents($this->_config_file, $config);
	}
	
	/**
	 * 读配置文件
	 *
	 */
	public function load_config()
	{
		$configs = parse_ini_file($this->_config_file);

		$this->set_host($configs['server_host'], $configs['server_port']);
		$this->time_diff = $configs['time_diff'];
		$this->mode = $configs['mode'];
		$this->_mac = $configs['mac'];
		$this->client_type = $configs['client_type'];
		$this->username = $configs['username'];
		$this->password = $configs['password'];
	}
	
	/**
	 * 解析http响应
	 *
	 */
	public function parse_http_reponse($response)
	{
		if ($this->client_type != 2)
		{
			return array('code'=>NULL, 'text'=>$response);
		}
		else
		{
			$tmp = explode("\r\n", $response);
			if (isset($tmp[1]))
				return array('code'=>$tmp[0], 'text'=>$tmp[1]);
			else
				return array('code'=>NULL, 'text'=>$tmp[0]);
		}
	}
}